﻿// Decompiled with JetBrains decompiler
// Type: Netick.Unity.NetworkScene
// Assembly: Netick.Unity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E128C7FD-39ED-4452-86AC-6EC748457030
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.xml

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;

#nullable disable
namespace Netick.Unity;

internal class NetworkScene
{
  public NetworkSandbox Sandbox;
  public NetworkSceneOperation NetworkSceneOperation;
  public int SlotIndex;
  public bool IsMainScene;
  public Scene Scene;
  public int SceneIndex;
  public int LoadCounterId;
  public bool CreatePhysicsScene;
  public bool IsReady;
  public bool IsLoaded;
  public bool CheckedForDestroyedObjects;
  public Dictionary<int, NetworkObject> NetworkObjects = new Dictionary<int, NetworkObject>(100);
  public List<GameObject> Objects = new List<GameObject>(100);

  public NetworkScene(
    NetworkSandbox sandbox,
    bool isMainScene,
    int loadCounterId,
    bool createPhysicsScene,
    Scene scene,
    int slotIndex)
  {
    this.SlotIndex = slotIndex;
    this.Sandbox = sandbox;
    this.IsMainScene = isMainScene;
    this.Scene = scene;
    this.LoadCounterId = loadCounterId;
    this.CreatePhysicsScene = createPhysicsScene;
    this.SceneIndex = -1;
  }

  internal void InternalSwitchScene(int sceneBuildIndex, int sceneCounter)
  {
    if (this.Sandbox.IsServer)
    {
      for (int i = 0; i < this.Sandbox.NetworkSceneManager.NetworkedLoadedAdditiveScenes.Length; ++i)
        this.Sandbox.NetworkSceneManager.NetworkedLoadedAdditiveScenes[i] = SceneInfo.GetInvalid();
    }
    this.Sandbox.NetworkSceneManager.LoadedAdditiveScenes.Clear();
    this.Sandbox.NetworkSceneManager.PendingLoadScenes.Clear();
    this.Sandbox.NetworkSceneManager.PendingUnloadScenes.Clear();
    this.Sandbox.Events.InvokeOnSceneLoadStarted(this.Sandbox);
    StaticUnitySceneManager.SwitchScene(this.Sandbox, sceneBuildIndex, sceneCounter, this.Sandbox.Scenes);
    this.Sandbox.HasLoadScene = false;
  }

  internal void OnSceneLoaded(
    Scene scene,
    int sceneIndex,
    int sceneCounter,
    bool isSceneSwitch,
    bool callStartup,
    bool isRemoteAdditiveScene)
  {
    this.CheckedForDestroyedObjects = false;
    this.Objects.Clear();
    this.LoadCounterId = sceneCounter;
    this.Scene = scene;
    this.SceneIndex = sceneIndex;
    if (isSceneSwitch)
    {
      this.Sandbox.HasLoadScene = true;
      this.Sandbox.Scene = scene;
      this.Sandbox.MainSceneIndex = sceneIndex;
      this.Sandbox.MainSceneLoadIdCounter = sceneCounter;
      this.Sandbox.Physics = scene.GetPhysicsScene();
      this.Sandbox.Physics2D = scene.GetPhysicsScene2D();
    }
    this.Sandbox.NetworkSceneManager._cached.Clear();
    List<NetworkObject> objs = new List<NetworkObject>(100);
    this.GetSceneObjects(this.Scene, objs);
    objs.Sort((Comparison<NetworkObject>) ((x, y) => x._SceneId.CompareTo(y._SceneId)));
    int num = 1;
    foreach (NetworkObject networkObject in objs)
    {
      networkObject._RuntimeSceneId = num;
      ++num;
    }
    NetworkSandbox.EnsureSingleInstances(this.Scene, this.Sandbox);
    NetworkSandbox.GetNetworkListeners(this.Scene, this.Sandbox);
    if (this.Sandbox.IsPhysicsSteppedByNetick)
      this.Sandbox.LocalRigidbodyFixer.FindAllRigidbodies(this.Scene);
    if (callStartup)
      this.Sandbox.Events.InvokeOnStartup(this.Sandbox);
    if (isSceneSwitch)
    {
      foreach (NetworkObjectPool networkObjectPool in this.Sandbox.IdToPrefabPool.Values)
        networkObjectPool.Reload();
    }
    GameObject[] rootGameObjects = this.Scene.GetRootGameObjects();
    foreach (GameObject gameObject in rootGameObjects)
      this.InitializeSceneObject(gameObject, isRemoteAdditiveScene);
    if (this.Sandbox.IsClient)
    {
      foreach (NetworkObject entity in this.Sandbox.NetworkSceneManager._cached)
        this.Sandbox.ClientDestroyObject(entity);
      this.Sandbox.NetworkSceneManager._cached.Clear();
    }
    if (Network.StartMode == StartMode.MultiplePeers && !this.CreatePhysicsScene)
    {
      foreach (GameObject go in rootGameObjects)
        SceneManager.MoveGameObjectToScene(go, this.Sandbox.Scene);
    }
    if (isSceneSwitch)
    {
      this.Sandbox.Events.InvokeOnSceneLoaded(this.Sandbox);
      this.Sandbox.Engine.ResetForSceneSwitch();
    }
    if (Network.Instance._startMode == StartMode.MultiplePeers)
      this.Sandbox.AttachComponents(this.Sandbox.FindObjectsOfType<Component>(false));
    if (callStartup)
      return;
    this.NetworkSceneOperation.Scene = this.Scene;
    this.Sandbox.Events.InvokeOnSceneOperationDone(this.Sandbox, this.NetworkSceneOperation);
  }

  private void GetSceneObjects(Scene scene, List<NetworkObject> objs)
  {
    foreach (GameObject rootGameObject in this.Scene.GetRootGameObjects())
      this.GetChildObjectsNested(rootGameObject, objs);
  }

  private void GetChildObjectsNested(GameObject obj, List<NetworkObject> objs)
  {
    NetworkObject component = obj.GetComponent<NetworkObject>();
    if ((UnityEngine.Object) component != (UnityEngine.Object) null)
      objs.Add(component);
    for (int index = 0; index < obj.transform.childCount; ++index)
      this.GetChildObjectsNested(obj.transform.GetChild(index).gameObject, objs);
  }

  private void InitializeSceneObject(GameObject obj, bool isRemoteAdditiveObject)
  {
    this.InitializeSceneObjectNested(obj.gameObject, isRemoteAdditiveObject);
    for (int index = 0; index < obj.transform.childCount; ++index)
      this.InitializeSceneObject(obj.transform.GetChild(index).gameObject, isRemoteAdditiveObject);
  }

  private unsafe void InitializeSceneObjectNested(
    GameObject sceneObject,
    bool isRemoteAdditiveSceneObject)
  {
    NetworkObject component = sceneObject.GetComponent<NetworkObject>();
    if ((UnityEngine.Object) component == (UnityEngine.Object) null || component._RuntimeSceneId == -1 || !component.gameObject.activeInHierarchy && !this.Sandbox.Config.IncludeInactiveObjects || component.gameObject.scene != this.Scene)
    {
      this.Objects.Add(sceneObject);
    }
    else
    {
      component.InitLocally(this.Sandbox, this);
      ScenePendingObjectKey pendingObjectKey = new ScenePendingObjectKey()
      {
        SceneObjectId = component._RuntimeSceneId,
        SceneLoadId = this.LoadCounterId
      };
      if (this.Sandbox.IsClient)
      {
        Entity entity;
        if (this.Sandbox.IsClient && this.Sandbox.PendingSceneObjects.Remove(pendingObjectKey, ref entity))
        {
          int rawId = entity.RawId;
          int worldIndex = entity.WorldIndex;
          NetworkObjectMeta* entityUserMeta = (NetworkObjectMeta*) this.Sandbox.Engine.GetEntityUserMeta(entity);
          NetickEntityMeta* entityMeta = this.Sandbox.Engine.GetEntityMeta(entity);
          this.Sandbox.Engine.LinkEntity((INetickEntity) component, entity);
          this.Sandbox.Engine.ClientAddEntity((INetickEntity) component, rawId, worldIndex, true, *entityMeta);
          component.NetworkSetParent(entityUserMeta->ParentId);
          if (this.Sandbox.Config.SyncTransformOnSpawn)
          {
            Vector3 pos;
            Quaternion rot;
            this.Sandbox.GetEntityMetaPosRot(entityUserMeta, out pos, out rot);
            component.transform.position = pos;
            component.transform.rotation = rot;
          }
        }
        else
          this.Sandbox.Engine.CreateAndLinkEntityLocal((INetickEntity) component);
      }
      else
        this.Sandbox.Engine.CreateAndLinkEntityLocal((INetickEntity) component);
      if (this.Sandbox.IsClient && !this.IsMainScene && component.Entity.RawId == -1)
        this.Sandbox.NetworkSceneManager._cached.Add(component);
      this.NetworkObjects.Add(component._RuntimeSceneId, component);
      if (!this.Sandbox.Engine.IsServer)
        return;
      this.Sandbox.Engine.ServerAddEntity((INetickEntity) component, (Netick.NetworkPlayer) null, true);
    }
  }

  internal void DestroyAllObjects()
  {
    foreach (Entity entity in this.Sandbox.Engine.AllEntities.Values.ToList<Entity>())
    {
      NetworkObject userEntity = entity.UserEntity as NetworkObject;
      if (!((UnityEngine.Object) userEntity == (UnityEngine.Object) this.Sandbox.SandboxNetworkObject) && (!userEntity.IsPersistent || !userEntity.IsPrefabObject))
        this.Sandbox.Engine.DestroyEntity(entity, true, true);
    }
    foreach (GameObject gameObject in this.Objects)
    {
      if ((UnityEngine.Object) gameObject != (UnityEngine.Object) null && (UnityEngine.Object) gameObject.gameObject != (UnityEngine.Object) null)
      {
        foreach (Transform transform in gameObject.transform)
          transform.SetParent((Transform) null);
        UnityEngine.Object.Destroy((UnityEngine.Object) gameObject.gameObject);
      }
    }
    this.NetworkObjects.Clear();
    this.Objects.Clear();
  }

  internal void DestroySceneObjects()
  {
    foreach (NetworkObject networkObject in this.NetworkObjects.Values.ToList<NetworkObject>())
    {
      if (!((UnityEngine.Object) networkObject == (UnityEngine.Object) this.Sandbox.SandboxNetworkObject) && (UnityEngine.Object) networkObject != (UnityEngine.Object) null && (UnityEngine.Object) networkObject.gameObject != (UnityEngine.Object) null)
      {
        networkObject.transform.SetParent((Transform) null);
        this.Sandbox.Engine.DestroyEntity(networkObject.Entity, true, true);
      }
    }
    foreach (GameObject gameObject in this.Objects)
    {
      if ((UnityEngine.Object) gameObject != (UnityEngine.Object) null && (UnityEngine.Object) gameObject.gameObject != (UnityEngine.Object) null)
      {
        foreach (Transform transform in gameObject.transform)
          transform.SetParent((Transform) null);
        UnityEngine.Object.Destroy((UnityEngine.Object) gameObject.gameObject);
      }
    }
    this.NetworkObjects.Clear();
    this.Objects.Clear();
  }
}
